package sketch.generator;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import sketch.util.Checker;
import sketch.util.Randomness;

/**
 * This generator will nondeterministically explore all
 * given objects
 * */
public class NondetValueGenerator<T> extends ValueGenerator<T>{

	private List<T> values = new ArrayList<T>();
	
	//the explored index
	private List<Integer> explorIndexOrder = null;
	
	//the current exploring index
	private int currentIndex = 0;

	public NondetValueGenerator(T... values) {
		super();
		add(values);
	}
	
	public NondetValueGenerator(Collection<T> values) {
		super();
		for(T t : values) {
			this.add(t);
		}
	}
	
	public void add(T value) {
		values.add(value);
	}
	
	public void add(T...values) {
		for(T value : values) {
			add(value);
		}
	}
	
	@Override
	public T composeData() {
		throw new UnsupportedOperationException("composeData() is not supported in NondetValueGenerator yet!");
	}

	@Override
	protected T generateNext() {
		if(!hasNext()) {
			throw new IterationException("Has no next() element!");
		}
		T nextItem = this.values.get(this.explorIndexOrder.get(this.currentIndex));
		//increase the current index
		this.currentIndex = this.currentIndex + 1;
		return nextItem;
	}

	@Override
	public boolean hasNext() {
		if(this.explorIndexOrder == null) {
			this.explorIndexOrder = new ArrayList<Integer>();
			for(int index : this.createRandomSeries()) {
			    this.explorIndexOrder.add(index);
			}
		}
		if(this.explorIndexOrder.isEmpty()) {
			return false;
		}
		return (this.currentIndex <= (this.explorIndexOrder.size() - 1));
	}
	
	@Override
	public void reset() {
		super.reset();
		this.explorIndexOrder = null;
		this.currentIndex = 0;
	}
	
	private int[] createRandomSeries() {
		int[] retSeries = new int[values.size()];
		
		Set<Integer> intSet = new HashSet<Integer>();
		for(int i = 0; i < values.size(); i++) {
			intSet.add(i);
		}
		
		for(int i = 0; i < retSeries.length; i++) {
			Checker.checkTrue(!intSet.isEmpty(), "The int set should not be empty!");
			int picked = Randomness.randomSetMember(intSet);
			retSeries[i] = picked;
			//remove that from the int set
			intSet.remove(picked);
		}
		
		return retSeries;
	}
	/**
	 * A small testing driver
	 * */
	public static void main(String[] args) {
		NondetValueGenerator<Integer> generator = new NondetValueGenerator<Integer>(4, 5, 6, 9, 10);
		int[] randoms = generator.createRandomSeries();
		for(int random : randoms) {
			System.out.println(random);
		}
		
		while(generator.hasNext()) {
			System.out.println("value: " + generator.next());
		}
	}

	@Override
	public List<T> nextWrappedValue() {
		T t = this.generateNext();
		return Collections.singletonList(t);
	}
}
